package com.eastcom.groovy.task.taskdirector.file.txt
import com.eastcom.groovy.config.TaskConfig
import com.eastcom.groovy.context.ServerContext
import com.eastcom.groovy.context.TaskContext
import com.eastcom.groovy.provider.DbContextProvider
import com.eastcom.groovy.provider.DynamicBeanDomianProvider
import com.eastcom.groovy.provider.SpringContextProvider
import com.eastcom.groovy.task.Task
import com.eastcom.groovy.tools.db.DbEngine
import com.eastcom.groovy.tools.db.DbInfo
import com.eastcom.groovy.tools.db.Table
import com.eastcom.groovy.tools.file.GroovyUtil
import com.eastcom.groovy.tools.file.JaxbUtil
import com.eastcom.groovy.tools.TaskUtil
import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.dao.DataAccessException
import org.springframework.jdbc.core.ResultSetExtractor
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor

import java.io.IOException;
import java.io.Serializable;
import java.sql.CallableStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Timestamp
import java.sql.Types
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor
import java.util.regex.Matcher
import java.util.regex.Pattern

import javax.xml.bind.annotation.XmlAccessorType
import javax.xml.bind.annotation.XmlElement
import javax.xml.bind.annotation.XmlRootElement

@XmlRootElement(name = "resource")
@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
class ResourceList {
	@XmlElement(name = "dst")
	List<DstResource> dstResource
	@XmlElement(name = "src")
	List<SrcResource> srcResource
	public boolean init(String jobId){
		if(dstResource != null){
			dstResource.each {
				DstResource dst = it
				dst.init()
			}
		}
		if(srcResource != null){
			srcResource.each {
				it.init()
				TaskContext.getTaskConfig().put("src."+it.getName(), it)
			}
		}
	}
}

@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
public class DstResource{
	private static Log logger = LogFactory.getLog(DstResource.class)
	@XmlElement(name = "name")
	String name
	@XmlElement(name = "type")
	String type
	@XmlElement(name = "dstDb")
	String dstDb
	@XmlElement(name = "dstTb")
	String dstTb
	@XmlElement(name = "srcNames")
	String srcNames
	@XmlElement(name = "dstFields")
	String dstFields
	@XmlElement(name = "timeFormat")
	String timeFormat
	@XmlElement(name = "configureInsertSql")
	String configureInsertSql
	@javax.xml.bind.annotation.XmlTransient
	List<String> dstFieldsList = new ArrayList()
	@javax.xml.bind.annotation.XmlTransient
	List<Integer> dstFieldsTypeList
	@javax.xml.bind.annotation.XmlTransient
	int[] sqlTypes
	@javax.xml.bind.annotation.XmlTransient
	String insertSql = ""
	@javax.xml.bind.annotation.XmlTransient
	String[] srcNameArr
	public boolean init(){
		dstFieldsTypeList = loadDb(dstDb, dstTb);
		if(dstFieldsTypeList == null){
			return false
		}
		//源数据表
		srcNameArr = srcNames.split("\\s*,\\s*")
		if(dstFields == null){
			logger.error("目的数据库字段不能为空！")
			return false
		}
		int i = 0
		sqlTypes = new int[dstFieldsTypeList.size()]
		dstFieldsTypeList.each {
			sqlTypes[i++] = it
		}
		if (configureInsertSql == null || configureInsertSql.equals("")) {
			insertSql = makeSql(dstFieldsList, dstTb)
		} else {
			insertSql = configureInsertSql
			dstFieldsList.clear()
			String reg = "(?<=[\\(,])(\\s*\\w+\\s*)(?=[\\),])"
			Pattern pat = Pattern.compile(reg);
			Matcher mat = pat.matcher(configureInsertSql);
			boolean rs = mat.find();
			for(int h = 1; h <= mat.groupCount(); h++){
				System.out.println(mat.group(h));
				dstFieldsList.add(mat.group(h))
			}
			dstFieldsTypeList.clear()
			dstFieldsList.each {
				int index = ServerContext.dbMap.get(dstDb).getTables().get(dstTb).feildName.indexOf(it)
				dstFieldsTypeList.add(ServerContext.dbMap.get(dstDb).getTables().get(dstTb).feildType.get(index))
			}
		}
		logger.debug(insertSql)
	}

	List<Integer> loadDb(String dstDb, String dstTb) {
		String db = dstDb.trim()
		String tb = dstTb.trim()

		List<Integer> dstFieldTypeList = new ArrayList<>()
		if (ServerContext.dbMap.containsKey(db)) {
			DbInfo dbInfo = ServerContext.dbMap.get(db)
			Map<String, Table> tables = dbInfo.tables
			if (tables.containsKey(db)) {
				println "已存在表[" + tb + "]信息。。。"
			} else {
				println "正在加载表[" + tb + "]信息。。。"
				DbContextProvider dbContextProvider = new DbContextProvider()
				boolean result = dbContextProvider.loadExternDbSource(dstDb, dstTb)
				if(result){
					println "查询表[" + tb + "]信息成功！"
				}else{
					println "查询表[" + tb + "]信息失败！"
					return null
				}
			}
		} else {
			println "正在加载表[" + tb + "]信息。。。"
			DbContextProvider dbContextProvider = new DbContextProvider()
			if (!dbContextProvider.loadExternDbSource(db, tb)) {
				println "加载表[" + db + "]信息失败！"
				return null
			}
			println "查询表[" + db + "]信息成功！"
		}
		if(dstFields.trim().equalsIgnoreCase("ALL")){
			logger.debug("目的数据库配置ALL，使用所有字段!")
			dstFieldsList.addAll(ServerContext.dbMap.get(dstDb.trim()).tables.get(dstTb.trim()).feildName)
			logger.debug("dstFieldList.size="+dstFieldsList.size())
		}else {
			String[] fieldArr  = dstFields.split("\\s*,\\s*")
			fieldArr.each { dstFieldsList.add(it) }
		}
		if (!checkDstDbFeilds(db, tb, dstFieldsList)) {
			println "配置表字段与实际或者缓存中不一致！请检查配置和数据库信息是否一致！"
			return null
		}

		dstFieldsList.each {
			int index = ServerContext.dbMap.get(db).getTables().get(tb).feildName.indexOf(it)
			dstFieldTypeList.add(ServerContext.dbMap.get(db).getTables().get(tb).feildType.get(index))
		}
		return dstFieldTypeList
	}

	boolean checkDstDbFeilds(String db, String tb, List<String> dstFieldList) {
		if (ServerContext.dbMap.get(db).tables.get(tb).feildName.containsAll(dstFieldList)) {
			return true
		}
		return false
	}

	String makeSql(List<String> fieldList, String table) {
		StringBuffer sqlBuffer = new StringBuffer()
		int i = 0
		sqlBuffer.append("insert into " + table + "(")
		fieldList.each {
			sqlBuffer.append(it)
			i++
			if (i < fieldList.size()) {
				sqlBuffer.append(",")
			}
		}
		sqlBuffer.append(") values (")
		for (int s = 0; s < fieldList.size(); s++) {
			sqlBuffer.append("?")
			if (s < fieldList.size() - 1) {
				sqlBuffer.append(",")
			}
		}
		sqlBuffer.append(")")
		return sqlBuffer.toString()
	}
}

@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
public class SrcResource{
	@XmlElement(name = "name")
	String name
	@XmlElement(name = "fileNameRegex")
	String fileNameRegex
	@XmlElement(name = "filePath")
	String filePath
	@XmlElement(name = "fileTimeLimit")
	String fileTimeLimit
	@XmlElement(name = "fileEncode")
	String fileEncode
	@XmlElement(name = "recordRegexList")
	RecordRegex recordRegexList
	@XmlElement(name = "minLineCount")
	String minLineCount

	public boolean init(){
		recordRegexList.init()
	}
}

@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
public class RecordRegex{
	@XmlElement(name = "regex")
	List<Regex> regex

	public boolean init(){
		regex.each { it.init() }
	}
}

@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
public class RecordSpecVarList{
	@XmlElement(name = "var")
	List<String> varList
	@XmlElement(name = "sqlPlaceHolderIndex")
	String sqlPlaceHolderIndex

	@javax.xml.bind.annotation.XmlTransient
	List<Integer> sqlPlaceHolderList = new ArrayList()

	public boolean init(){
		String[] temp = sqlPlaceHolderIndex.split("\\s*,\\s*")
		temp.each {
			sqlPlaceHolderList.add(Integer.valueOf(it))
		}
	}
}



@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
public class Regex{
	@XmlElement(name = "pattern")
	String pattern
	@XmlElement(name = "sqlPlaceHolderIndex")
	String sqlPlaceHolderIndex
	@XmlElement(name = "groupId")
	String groupId
	@XmlElement(name = "timeFormat")
	String timeFormat

	@javax.xml.bind.annotation.XmlTransient
	List<Integer> sqlPlaceHolderList = new ArrayList()
	@javax.xml.bind.annotation.XmlTransient
	List<Integer> groupIdList = new ArrayList()

	public boolean init(){
		String[] temp = sqlPlaceHolderIndex.split("\\s*,\\s*")
		temp.each {
			sqlPlaceHolderList.add(Integer.valueOf(it))
		}
		temp = groupId.split("\\s*,\\s*")
		temp.each {
			groupIdList.add(Integer.valueOf(it))
		}
		
	}
}
public boolean initJob(String jobId){
	String configFileName = TaskContext.taskMap.get(jobId).getTaskConfig().getExtern().getConfig().getConfigFile()
	String configRootPath = TaskContext.taskMap.get(jobId).getRootPath()
	println configFileName+"----"+configRootPath+"----"+jobId
	ResourceList resourceList = JaxbUtil.converyFileToJavaBean(configRootPath+"/"+configFileName, "UTF-8", ResourceList.class)
	resourceList.init(jobId)
	TaskContext.taskConfig.put(jobId+".resourceList", resourceList)
}

/**
 * 鎵ц鏂规硶
 * @param jobId
 */
public boolean doJob(String jobId) {
	DbEngine dbEngine = SpringContextProvider.getBean("dbEngine")
	Log logger = LogFactory.getLog(this.getClass())
	ResourceList resourceList = TaskContext.taskConfig.get(jobId+".resourceList")
	resourceList.dstResource.each {
		DstResource dst = it
		String dstName = dst.getName()
		dst.getSrcNameArr().each {
			SrcResource src = TaskContext.getTaskConfig().get("src."+it)


			println "dfdfdfd"+src
			dbEngine = (DbEngine) SpringContextProvider.getBean("dbEngine")
			String encode = src.getFileEncode()
			String fileNameRegex = src.getFileNameRegex()
			String path = src.filePath
			String timeLimit = src.fileTimeLimit
			int minParseline = Integer.valueOf(src.minLineCount)

			List<Regex> regexList = src.getRecordRegexList().regex
			logger.debug(path);
			File dirs = new File(path);
			if(! dirs.isDirectory()){
				logger.debug("inviland dir!");
				return;
			}
			File[] f2 = dirs.listFiles(new FilenameFilter() {

						@Override
						public boolean accept(File dir, String name) {
							// TODO 自动生成的方法存根
							if(name.matches(fileNameRegex)){
								logger.debug("recieve file:"+name);
								return true;
							}
							return false;
						}
					});
			if(f2 == null){
				logger.debug("not any file of regex name found!");
				return;
			}
			Calendar fileTime = Calendar.getInstance();
			Calendar fileLimitTime = Calendar.getInstance();
			long ft = Long.valueOf(timeLimit);
			fileLimitTime.setTimeInMillis(new Date().getTime() - ft);
			for(File file2: f2){
				long time = file2.lastModified();
				fileTime.setTimeInMillis(time);
				if(fileTime.before(fileLimitTime)){
					logger.debug("时间超出！");
					continue;
				}
				String fileNameTime = null;
				List<String> valueList = new ArrayList<String>();


				BufferedReader reader = null;
				try {
					reader = new BufferedReader(new InputStreamReader(new FileInputStream(file2), encode));
				} catch (UnsupportedEncodingException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				} catch (FileNotFoundException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				StringBuilder context = new StringBuilder();
				String line = null;
				boolean isFileEnd = false;
				int counts = 0
				boolean rs = false
				while(true){

					for(int j = 0; j < minParseline; j++){
						try {
							line = reader.readLine();
						} catch (IOException e) {
							// TODO 自动生成的 catch 块
							e.printStackTrace();
						}
						if(line == null){
							isFileEnd = true;
							break;
						}
						context.append(line+"\n");
					}
					regexList.each {
						Regex regex = it
						String reg = regex.getPattern()
						Pattern pat = Pattern.compile(reg.toString());
						int a = 0
						Matcher mat = pat.matcher(context.toString());
						rs = mat.find();
						if(rs){
							context = new StringBuilder();
							for(int gr: regex.getGroupIdList()){
								String value = mat.group(gr);
								int sqlPlace = regex.getSqlPlaceHolderList().get(a)
								println sqlPlace+counts
								valueList.add(sqlPlace+counts,value);
								a++
							}
							counts+=regex.getGroupIdList().size()
						}else{
							logger.debug("不匹配！"+regex.getPattern()+"-------"+context.toString());
						}
					}
					if(isFileEnd){
						logger.debug("文件已经读完！");
						break;
					}
				}

				try {
					if(!valueList.isEmpty()){
						insertData(valueList,dst);
					}
				} catch (ParseException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			}
		}
	}
}

int[] insertData(List<String> valueList,DstResource dst) throws ParseException{
	Log logger = LogFactory.getLog(this.getClass())
	DbEngine dbEngine = SpringContextProvider.getBean("dbEngine")
	logger.debug("list size="+valueList.size());
	int[] res = null;

	logger.debug(ServerContext.dbMap);
	DbInfo dbInfo = ServerContext.dbMap.get(dst.getDstDb());
	logger.debug(dbInfo);
	Table table = dbInfo.getTables().get(dst.getDstTb());
	List<String> primColumn = table.getPrimaryKeys();
	logger.debug(table);

	String timeFormats = dst
	logger.debug(timeFormats);
	//		logger.debug(timeFormatArr[0]+"---"+timeFormatArr[1]);
	int index = 0;
	List<Object[]> paramList = new ArrayList<Object[]>();
	int[] sqlType = new int[dst.getSqlTypes().length]
	dst.getSqlTypes().each { println it }
	for(int i = 0; i < valueList.size()/dst.getSqlTypes().length; i++){
		Object[] sqlParam = new Object[dst.getSqlTypes().length];
		for(int j = 0; j < dst.getSqlTypes().length; j++){
			Integer type = dst.getSqlTypes()[j];
			String value = valueList.get(index);
			index++;
			if(value == null){
				sqlParam[j] = null;
				continue;
			}
			sqlType[j] = type;
			switch (type) {
				case Types.TIMESTAMP:
				//目前多个regex只支持一种时间格式
					int id = 0;
					boolean isContinue = true;
					java.util.Date date = null;
					SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dst.getTimeFormat());
					date = simpleDateFormat.parse(value);
					isContinue = false;
					logger.debug(date.toLocaleString());
					SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					String string = simpleDateFormat2.format(date);
					logger.debug(string);
					Timestamp timestamp = Timestamp.valueOf(string);
					sqlParam[j] = timestamp;
					break;
				case Types.VARCHAR:
				case Types.NVARCHAR:
					sqlParam[j] = value;
					break;
				case Types.DECIMAL:
					sqlParam[j] = BigDecimal.valueOf(Double.valueOf(value));
					break;
				case Types.NUMERIC:
					sqlParam[j] = BigDecimal.valueOf(Double.valueOf(value));
					break;
				case Types.INTEGER:
					sqlParam[j] = Integer.valueOf(value);
					break;
				case Types.DOUBLE:
					sqlParam[j] = Double.valueOf(value);
				default:
					break;
			}
		}
		paramList.add(sqlParam);
	}
	dbEngine.getJdbcUtil().setDataSource(DynamicBeanDomianProvider.getBean("oracle_39_nhm"))
	try {
		res = dbEngine.getJdbcUtil().batchUpdate(dst.getInsertSql(), paramList, sqlType);

	} catch (Exception e) {
		// TODO: handle exception
		logger.error(e.getMessage());
	}
	return res;
}

public Timestamp getFirstDayOfSpecialMonth(List<String> afterNow) {
	Timestamp timestamp = new Timestamp(new Date().getTime())
	Calendar calendar = Calendar.getInstance()
	calendar.setTime(timestamp)
	calendar.add(Calendar.MONTH, Integer.valueOf(afterNow.get(0)))
	calendar.set(Calendar.DAY_OF_MONTH, 1)
	calendar.set(Calendar.HOUR_OF_DAY, 0)
	calendar.set(Calendar.MINUTE, 0)
	calendar.set(Calendar.SECOND, 0)
	calendar.set(Calendar.MILLISECOND, 0)
	return new Timestamp(calendar.getTime().getTime())
}
//timeFormat, String afterNow
public String getContextByMonth(List<String> param) {
	Log logger = LogFactory.getLog(this.class)
	param.each {
		logger.debug("param = " + it)
	}
	Calendar calendar = Calendar.getInstance()
	calendar.setTime(new Date())
	calendar.add(Calendar.MONTH, Integer.valueOf(param.get(0)))
	calendar.set(Calendar.DAY_OF_MONTH, 1)
	calendar.set(Calendar.HOUR_OF_DAY, 0)
	calendar.set(Calendar.MINUTE, 0)
	calendar.set(Calendar.SECOND, 0)
	calendar.set(Calendar.MILLISECOND, 0)
	SimpleDateFormat dateFormat = new SimpleDateFormat(param.get(1))
	String result = dateFormat.format(calendar.getTime())
	return result
}

//2014-04-11 00:00:00
public Timestamp getTimeParamByDay(List<String> afterNow) {
	Timestamp timestamp = new Timestamp(new Date().getTime())
	Calendar calendar = Calendar.getInstance()
	calendar.setTime(timestamp)
	calendar.add(Calendar.DAY_OF_YEAR, Integer.valueOf(afterNow.get(0)))
	calendar.set(Calendar.HOUR_OF_DAY, 0)
	calendar.set(Calendar.MINUTE, 0)
	calendar.set(Calendar.SECOND, 0)
	calendar.set(Calendar.MILLISECOND, 0)
	return new Timestamp(calendar.getTime().getTime())
}
public String getTimeContextByDay(List<String> param) {
	Calendar calendar = Calendar.getInstance()
	calendar.setTime(new Date())
	calendar.add(Calendar.MONTH, Integer.valueOf(param.get(0)))
	calendar.set(Calendar.HOUR_OF_DAY, 0)
	calendar.set(Calendar.MINUTE, 0)
	calendar.set(Calendar.SECOND, 0)
	calendar.set(Calendar.MILLISECOND, 0)
	SimpleDateFormat dateFormat = new SimpleDateFormat(param.get(1))
	String result = dateFormat.format(calendar.getTime())
	return result
}




